package edu.hit;

import static edu.hit.Utils.Utils.*;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.List;


public class Main {
  public static void main(String[] args){
    // You can use print statements as follows for debugging, they'll be visible when running tests.
    System.out.println("Logs from your program will appear here!");

    //  Uncomment this block to pass the first stage
        ServerSocket serverSocket = null;
        Socket clientSocket = null;
        int port;

        //--port <PORT> --replicaof <MASTER_HOST> <MASTER_PORT>
        if (args.length >= 2 && args[0].equalsIgnoreCase("--port")) {
            port = Integer.parseInt(args[1]);
            if(args.length == 5 && args[2].equalsIgnoreCase("--replicaof")){
                Configuration.configureReplica(new InetSocketAddress(args[3], Integer.parseInt(args[4])));
            }
        } else {
            port = 6379;
        }

        if(Configuration.getRole().equalsIgnoreCase("slave")){
            InetAddress masterAddress = Configuration.getMaster().getAddress();
            int masterPort = Configuration.getMaster().getPort();
            try(Socket socket = new Socket(masterAddress,masterPort);
                OutputStreamWriter writer = new OutputStreamWriter(socket.getOutputStream());
                BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()))
            ) {


                writer.write(generateArrayString(List.of("ping")).convert());

                writer.write(generateArrayString(List.of("REPLCONF","listening-port",String.valueOf(masterPort))).convert());

                writer.write(generateArrayString(List.of("REPLCONF","capa","psync2")).convert());

                writer.write(generateArrayString(List.of("PSYNC","?","-1")).convert());
                writer.flush();

            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }

        try {
          serverSocket = new ServerSocket(port);
          System.out.println("Server port " + serverSocket.getLocalPort() + " is listening");
          // Since the tester restarts your program quite often, setting SO_REUSEADDR
          // ensures that we don't run into 'Address already in use' errors
          serverSocket.setReuseAddress(true);
          // Wait for connection from client.

            while(true){
                clientSocket = serverSocket.accept();
                System.out.println("new client connected");
                new ClientHandler(clientSocket).start();
            }






        } catch (IOException e) {
          System.out.println("IOException: " + e.getMessage());
        } finally {
          try {
            if (clientSocket != null) {
              clientSocket.close();
            }
          } catch (IOException e) {
            System.out.println("IOException: " + e.getMessage());
          }
        }
  }
}
